use std::collections::VecDeque;

use godot::{classes::{CanvasLayer, Control, ICanvasLayer}, prelude::*};
use zfwk_macros::sname;




#[derive(GodotClass)]
#[class(init, base=CanvasLayer)]
pub struct Toaster {
    base: Base<CanvasLayer>,

    #[export]
    toast_prefab: Option<Gd<PackedScene>>,
    #[export]
    max_count: i32,
    #[export]
    container: Option<Gd<Control>>,

    toasts: VecDeque<(Gd<Control>, f64)>,
}

#[godot_api]
impl ICanvasLayer for Toaster {
	fn process(&mut self, delta: f64) {
		for _ in 0..self.toasts.len() {
			let (mut toast, mut duration) = self.toasts.pop_front().unwrap();
			duration -= delta;
			if duration < 0.0 {
				toast.queue_free();
				continue;
			} else if duration <= 1.0 {
				toast.set_modulate(Color::from_rgba(1.0, 1.0, 1.0, duration as f32));
			}
			self.toasts.push_back((toast, duration));
		}
	}
}

#[godot_api]
impl Toaster {
    #[func]
    pub fn make_text(&mut self, message: String, duration: f64) {
        if let Some((mut toast, mut container)) = self
            .toast_prefab
            .as_ref()
            .and_then(|p| p.instantiate())
			.and_then(|n| n.try_cast::<Control>().ok())
            .zip(self.container.clone())
        {
			let max = self.max_count as usize;
			while self.toasts.len() >= max {
				let (mut node, _) = self.toasts.pop_front().unwrap();
				node.queue_free();
			}

            toast.call(&sname!(c"set_message"), &[message.to_variant()]);
            self.toasts.push_back((toast.clone(), duration));
            container.add_child(&toast);
        } else {
            godot_error!("Toast prefab or toast container not specified.")
        }
    }
}
